﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace theguineasyndrome
{
    abstract public class LiquidDrop : ILevelObject
    {
        protected Level level;
        protected Texture2D texture;
        private Vector2 position;
        private Vector2 speed;
        private Vector2 nextDropSpeed;
        private float lifeTime;
        protected int popTime;
        private bool dead;
        private ObstacleElement killingObstacle;
        protected Portal currentPortal;

        protected Rectangle srcRect;
        protected Rectangle rectangle;

        protected Color color;
        protected Vector2 size;
        protected float radius;
        protected float weight;

        protected static RasterizerState scissor = new RasterizerState() { ScissorTestEnable = true };
        protected static Rectangle voidRectangle = new Rectangle();

        public LiquidDrop(Level level, Texture2D texture, Vector2 position, Vector2 speed, float lifeTime, int popTime)
        {
            this.level = level;
            this.texture = texture;
            this.position = position;
            this.speed = speed;
            this.lifeTime = lifeTime;
            this.popTime = popTime;
            dead = false;

            srcRect = new Rectangle(0, 0, texture.Width, texture.Height);
        }

        public virtual void Update(GameTime gameTime)
        {
            int age = (int)gameTime.TotalGameTime.TotalMilliseconds - popTime;
            if (age > 5000)
                dead = true;

            speed.Y += (float)gameTime.ElapsedGameTime.TotalMilliseconds * weight;
            position += speed;

            Utils.Pair<ObstacleElement, bool> collidingObstacle = level.getFirstCollidingObstacle(position, radius);

            currentPortal = null;

            if (collidingObstacle.Second)
                collidingObstacle.First.repulseLiquidDrop(this);

            rectangle.X = (int)position.X;
            rectangle.Y = (int)position.Y;
        }

        public virtual void Draw(SpriteBatch spriteBatch, Camera camera)
        {
            if (currentPortal != null)
            {
                spriteBatch.End();
                spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, null, null, scissor);

                switch(currentPortal.getSide())
                {
                    case LevelElement.Side.LEFT:
                    {
                        int width = (int)(camera.getRelative(new Vector2(currentPortal.CenterX, 0)).X - camera.Left * 2);

                        if (width > 0 && width <= camera.Width)
                            spriteBatch.GraphicsDevice.ScissorRectangle = new Rectangle(0, 0, width, (int)camera.Height);

                        else
                            spriteBatch.GraphicsDevice.ScissorRectangle = voidRectangle;
                    }
                    break;

                    case LevelElement.Side.RIGHT:
                    {
                        int x = (int)(camera.getRelative(new Vector2(currentPortal.CenterX, 0)).X - camera.Left * 2);
                        int width = (int)(camera.Width - x);

                        if (width > 0 && width <= camera.Width)
                            spriteBatch.GraphicsDevice.ScissorRectangle = new Rectangle(x, 0, width, (int)camera.Height);

                        else
                            spriteBatch.GraphicsDevice.ScissorRectangle = voidRectangle;
                    }
                    break;

                    case LevelElement.Side.TOP:
                    {
                        int height = (int)(camera.getRelative(new Vector2(0, currentPortal.CenterY)).Y - camera.Top * 2);

                        if (height > 0 && height <= camera.Height)
                            spriteBatch.GraphicsDevice.ScissorRectangle = new Rectangle(0, 0, (int)camera.Width, height);

                        else
                            spriteBatch.GraphicsDevice.ScissorRectangle = voidRectangle;
                    }
                    break;

                    case LevelElement.Side.BOTTOM:
                    {
                        int y = (int)(camera.getRelative(new Vector2(0, currentPortal.getElement().Bottom)).Y - camera.Top * 2);
                        int height = (int)(camera.Height - y);

                        if (height > 0 && height <= camera.Height)
                            spriteBatch.GraphicsDevice.ScissorRectangle = new Rectangle(0, y, (int)camera.Width, height);

                        else
                            spriteBatch.GraphicsDevice.ScissorRectangle = voidRectangle;
                    }
                    break;
                }
            }

            float angle = getAngle();
            spriteBatch.Draw(texture, camera.getDstRect(rectangle), srcRect, color, angle, size / 2, SpriteEffects.None, 0);

            if (currentPortal != null)
            {
                spriteBatch.End();
                spriteBatch.Begin();
            }
        }

        public Vector2 Position
        {
            get { return position; }
            set { position = value; rectangle.X = (int)position.X; rectangle.Y = (int)position.Y; }
        }

        public float X
        {
            get { return position.X; }
            set { position.X = value; rectangle.X = (int)value; }
        }

        public float Y
        {
            get { return position.Y; }
            set { position.Y = value; rectangle.Y = (int)value; }
        }

        public Vector2 Speed
        {
            get { return speed; }
            set { speed = value; }
        }

        public float SpeedX
        {
            get { return speed.X; }
            set { speed.X = value; }
        }

        public float SpeedY
        {
            get { return speed.Y; }
            set { speed.Y = value; }
        }

        public Vector2 NextDropSpeed
        {
            get { return nextDropSpeed; }
            set { nextDropSpeed = value; }
        }

        public float Left
        {
            get { return position.X - radius; }
        }

        public float Right
        {
            get { return position.X + radius; }
        }

        public float Top
        {
            get { return position.Y - radius; }
        }

        public float Bottom
        {
            get { return position.Y + radius; }
        }

        public float getAngle()
        {
            return Utils.PolarCoordinates.fromCartesian(speed).Y;
        }

        public float getRadius()
        {
            return radius;
        }

        public bool isDead()
        {
            return dead;
        }

        public void setKillingObstacle(ObstacleElement killingObstacle)
        {
            dead = true;
            this.killingObstacle = killingObstacle;
        }

        public ObstacleElement getKillingObstacle()
        {
            return killingObstacle;
        }

        public float getLifeTime()
        {
            return lifeTime;
        }

        public float Depth
        {
            get { return position.Y + radius; }
        }

        public Portal CurrentPortal
        {
            get { return currentPortal; }
            set { currentPortal = value; }
        }

        public void queueDrawing(Camera camera)
        {
            if (camera.isVisible(rectangle))
                level.queueObjectDrawing(this);
        }
    }
}
